/*
 * Copyright (C) 2006 Johan Maasing johan at zoom.nu Licensed under the Apache
 * License, Version 2.0 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law
 * or agreed to in writing, software distributed under the License is
 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package nu.zoom.catonine.desktop.rule;

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map.Entry;

import javax.swing.JButton;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import nu.zoom.catonine.fontchooser.FontChooserFactory;
import nu.zoom.catonine.stylerule.StyleRule;
import nu.zoom.catonine.stylerule.StyleRules;
import nu.zoom.catonine.stylerule.StyleRulesListModel;
import nu.zoom.catonine.stylerule.StyleRulesManager;
import nu.zoom.catonine.stylerule.StyleRulesManagerListener;
import nu.zoom.catonine.swing.rule.ConfigPanel;
import nu.zoom.gal.error.ErrorReporter;
import nu.zoom.swing.action.AbstractTypedAction;
import nu.zoom.swing.desktop.Workbench;
import nu.zoom.swing.desktop.WorkbenchFrame;
import nu.zoom.swing.desktop.WorkbenchFrameListener;
import nu.zoom.ui.Resources;
import nu.zoom.ui.Resources.ResourceNotFoundException;

/**
 * A panel for displaying the known collections of style rules.
 * 
 * @author "Johan Maasing" &lt;johan@zoom.nu&gt;
 * 
 */
public class StyleRulesManagerComponent extends JPanel implements
		ListSelectionListener, WorkbenchFrameListener,
		StyleRulesManagerListener {

	private static final long serialVersionUID = 1L;
	private final Workbench workbench;
	private final FontChooserFactory fontChooserFactory;
	private final ErrorReporter errorReporter;
	private JList stylesList;
	private JButton deleteButton;
	private JButton editButton;
	private final Resources messages;
	private StyleRulesManager manager;
	private HashMap<StyleRules, WorkbenchFrame> editorFrames = new HashMap<StyleRules, WorkbenchFrame>();
	private ConfigPanel configPanel = null;

	public StyleRulesManagerComponent(final StyleRulesManager manager,
			final Resources messages, final Workbench workbench,
			final FontChooserFactory fontChooserFactory,
			final ErrorReporter errorReporter) throws ResourceNotFoundException {
		super(new BorderLayout());
		this.workbench = workbench;
		this.messages = messages;
		this.manager = manager;
		this.errorReporter = errorReporter;
		this.fontChooserFactory = fontChooserFactory;
		stylesList = new JList(new StyleRulesListModel(manager,
				false));
		stylesList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		stylesList.addMouseListener(new MouseAdapter() {

			@Override
			public void mouseClicked(java.awt.event.MouseEvent e) {
				super.mouseClicked(e);
				if (e.getClickCount() > 1) {
					editStyleRules();
					e.consume();
				}
			}
		});
		stylesList.getSelectionModel().addListSelectionListener(this);
		JScrollPane listScroller = new JScrollPane(stylesList);

		JButton addButton = new JButton(new AddStyleRulesAction(messages));

		deleteButton = new JButton(new DeleteStyleRulesAction(messages));
		deleteButton.setEnabled(false);

		editButton = new JButton(new EditStyleRulesAction(messages));

		JPanel buttonPanel = new JPanel(new FlowLayout());
		buttonPanel.add(addButton);
		buttonPanel.add(deleteButton);
		buttonPanel.add(editButton);

		add(listScroller, BorderLayout.CENTER);
		add(buttonPanel, BorderLayout.SOUTH);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * javax.swing.event.ListSelectionListener#valueChanged(javax.swing.event
	 * .ListSelectionEvent)
	 */
	@Override
	public void valueChanged(ListSelectionEvent e) {
		if (stylesList.getSelectedIndex() == -1) {
			editButton.setEnabled(false);
			deleteButton.setEnabled(false);
		} else {
			editButton.setEnabled(true);
			deleteButton.setEnabled(true);
		}
	}

	private void newStyleRules() {
		try {
			StyleRules styleRules = new StyleRules(
					messages.getMessage("nu.zoom.catonine.configurations.new"));
			manager.add(styleRules);
			editStyleRules(styleRules);
		} catch (ResourceNotFoundException resourceNotFoundException) {
			// TODO: add logging
		}
	}

	private void deleteStyleRules() {
		StyleRules selectedRules = (StyleRules) stylesList.getSelectedValue();
		if (selectedRules != null) {
			WorkbenchFrame frame = editorFrames.get(selectedRules);
			if (frame != null) {
				frame.dispose();
			}
			manager.remove(selectedRules);
		}
	}

	private void editStyleRules() {
		StyleRules selectedRules = (StyleRules) stylesList.getSelectedValue();
		if (selectedRules != null) {
			editStyleRules(selectedRules);
		}
	}

	synchronized void editStyleRules(final StyleRules styleRules) {
		WorkbenchFrame editFrame = editorFrames.get(styleRules);
		if (editFrame != null) {
			if (!editFrame.isVisible()) {
				editFrame.setVisible(true);
			}
			editFrame.moveToFront();
		} else {
			try {
				configPanel = new ConfigPanel(workbench, fontChooserFactory,
						messages, errorReporter, styleRules,
						fontChooserFactory.getDefaultFont());
				editFrame = workbench.createWorkbenchFrame(
						"catonine.configframe", configPanel, null, true, true);
				String title = messages.format(
						"nu.zoom.catonine.configurations.edit.frame",
						styleRules.getName());
				editFrame.setTitle(title);
			} catch (ResourceNotFoundException resourceNotFoundException) {
				// TODO: add logging
			}
			editFrame.addFrameListener(this);
			editorFrames.put(styleRules, editFrame);
			editFrame.setVisible(true);
		}
	}

	@Override
	public synchronized void frameClosed(WorkbenchFrame frame) {
		Iterator<Entry<StyleRules, WorkbenchFrame>> entrySetIterator = editorFrames
				.entrySet().iterator();
		while (entrySetIterator.hasNext()) {
			Entry<StyleRules, WorkbenchFrame> entry = entrySetIterator.next();
			if (entry.getValue().equals(frame)) {
				entrySetIterator.remove();
			}
		}
	}

	@Override
	public void frameWillDispose(WorkbenchFrame frame) {
	}

	@Override
	public synchronized void styleRulesChanged(StyleRulesManager manager) {
		this.manager = manager;
		closeAllFrames();
		stylesList.setModel(new StyleRulesListModel(manager, false));
	}

	synchronized void closeAllFrames() {
		HashSet<StyleRules> openStyles = new HashSet<StyleRules>(
				editorFrames.keySet());
		for (StyleRules styleRules : openStyles) {
			WorkbenchFrame frame = editorFrames.get(styleRules);
			if (frame != null) {
				frame.dispose();
			}
		}
	}

	@Override
	public void frameDetached(WorkbenchFrame frame) {
	}

	@Override
	public void frameAttached(WorkbenchFrame frame) {
	}

	class AddStyleRulesAction extends AbstractTypedAction {

		private static final long serialVersionUID = 1L;

		public AddStyleRulesAction(Resources messages)
				throws ResourceNotFoundException {
			super();
			setName(messages.getMessage("nu.zoom.catonine.configurations.add"));
			setIcon(messages
					.getIcon("nu.zoom.catonine.configurations.add.icon"));
		}

		@Override
		public void actionPerformed(ActionEvent e) {
			newStyleRules();
		}
	}

	class DeleteStyleRulesAction extends AbstractTypedAction {

		private static final long serialVersionUID = 1L;

		public DeleteStyleRulesAction(Resources messages)
				throws ResourceNotFoundException {
			super();
			setName(messages
					.getMessage("nu.zoom.catonine.configurations.delete"));
			setIcon(messages
					.getIcon("nu.zoom.catonine.configurations.delete.icon"));
		}

		@Override
		public void actionPerformed(ActionEvent e) {
			deleteStyleRules();
		}
	}

	class EditStyleRulesAction extends AbstractEditStyleRulesAction {
		private static final long serialVersionUID = 4341319942693810215L;

		public EditStyleRulesAction(Resources messages)
				throws ResourceNotFoundException {
			super(messages);
		}

		@Override
		public void actionPerformed(ActionEvent e) {
			editStyleRules();
		}

	}

	public void createSimpleRule(StyleRules rules, String selectedText) {
		StyleRule rule = new StyleRule();
		rule.setPattern(".*" + selectedText + ".*");
		rules.add(rule);
		editStyleRules(rules);
		configPanel.setActiveRule(rule);
	}
}
